
import numpy as np
from common.config import pitchConfig as Config

from sklearn.cluster import DBSCAN
from sklearn.preprocessing import MinMaxScaler, StandardScaler
import pandas as pd
import time

class SmoothDecorator:

    def smooth(p3):
        def drop_noisy(df):
            df_copy = df.copy()
            df_describe = df_copy.describe()
            for column in df.columns:
                mean = df_describe.loc['mean', column]
                std = df_describe.loc['std', column]
                minvalue = mean - 3 * std
                maxvalue = mean + 3 * std
                df_copy = df_copy[df_copy[column] >= minvalue]
                df_copy = df_copy[df_copy[column] <= maxvalue]
            return df_copy

        def wrapper(X):
            print('SmoothProcess.smooth 进行中................')
            X = X.sort_values([Config.PitchAngle, Config.WindSpeed], ascending=[False,True])
            for i in np.linspace(-8, 8, 10 * 17 - 9):
                X[X[Config.PitchAngle] == round(i, 1)] = drop_noisy(X[X[Config.PitchAngle] == round(i, 1)])
            X = X.dropna(axis=0, how='all')

            return p3(X)
        return wrapper

    def drop_dbscan(p3):
        def wrapper(X):
            # columslist = [Config.WindSpeed, Config.ActPower, Config.PitchAngle]
            # X.columns = [columslist]
            x = X[[Config.WindSpeed, Config.ActPower]]
            scaler = StandardScaler().fit(x)
            scaled_features = scaler.transform(x)  # (x-均值)/标准差
            x = pd.DataFrame(data=scaled_features, columns=[Config.WindSpeed, Config.ActPower])
            start_time = time.time()

            eps = Config.dbscan_eps
            min_samples = Config.dbscan_min_samples

            # DBSCAN用法：DBSCAN(eps=0.5,min_samples=5,metric='euclidean',algorithm='auto',leaf_size=30,p=None,random_state=None)
            # eps:临域大小，min_samples:MinPtsMinPts参数，用于判断核心对象。metricmetric:用于计算距离。
            # algorithmalgorithm:用于计算两点间距离并找出最近邻点（'auto':自动取舍合适的算法。'ball_tree':用ball树搜索。'kd_tree':用kd树搜索。'brute':暴力搜索）
            mod = DBSCAN(eps=eps, min_samples=min_samples)
            y_pre = mod.fit_predict(x)
            print("y_pre: ", y_pre.sum())
            print("y_pre.shape: ", y_pre.shape)

            end_time = time.time()
            print(f"操作所花费时间: {end_time - start_time}")
            print(f"标签为： {y_pre}")

            X['type'] = y_pre
            X = X[X['type'] == 0]
            X.columns = [Config.WindSpeed, Config.ActPower, Config.PitchAngle, 'type']
            print('After drop_dbscan: ', len(X))
            return p3(X)
        return wrapper
    def curveSmooth(p3):
        def get_res(X, Y, Z, n):
            # 求方程系数
            sigma_x = 0  # x项求和
            for i in range(n): sigma_x += X[i]
            sigma_y = 0  # y项求和
            for i in range(n): sigma_y += Y[i]
            sigma_z = 0
            for i in range(n): sigma_z += Z[i]
            sigma_x2 = 0
            for i in range(n): sigma_x2 += X[i] * X[i]
            sigma_y2 = 0
            for i in range(n): sigma_y2 += Y[i] * Y[i]
            sigma_x3 = 0
            for i in range(n): sigma_x3 += X[i] * X[i] * X[i]
            sigma_y3 = 0
            for i in range(n): sigma_y3 += Y[i] * Y[i] * Y[i]
            sigma_x4 = 0
            for i in range(n): sigma_x4 += X[i] * X[i] * X[i] * X[i]
            sigma_y4 = 0
            for i in range(n): sigma_y4 += Y[i] * Y[i] * Y[i] * Y[i]
            sigma_x_y = 0
            for i in range(n): sigma_x_y += float(X[i] * Y[i])
            sigma_x_y2 = 0
            for i in range(n): sigma_x_y2 += float(X[i] * Y[i] * Y[i])
            sigma_x_y3 = 0
            for i in range(n): sigma_x_y3 += float(X[i] * Y[i] * Y[i] * Y[i])
            sigma_x2_y = 0
            for i in range(n): sigma_x2_y += float(X[i] * X[i] * Y[i])
            sigma_x2_y2 = 0
            for i in range(n): sigma_x2_y2 += float(X[i] * X[i] * Y[i] * Y[i])
            sigma_x3_y = 0
            for i in range(n): sigma_x3_y += float(X[i] * X[i] * X[i] * Y[i])
            sigma_z_x2 = 0
            for i in range(n): sigma_z_x2 += float(Z[i] * X[i] * X[i])
            sigma_z_y2 = 0
            for i in range(n): sigma_z_y2 += float(Z[i] * Y[i] * Y[i])
            sigma_z_x_y = 0
            for i in range(n): sigma_z_x_y += float(Z[i] * X[i] * Y[i])
            sigma_z_x = 0
            for i in range(n): sigma_z_x += float(Z[i] * X[i])
            sigma_z_y = 0
            for i in range(n): sigma_z_y += float(Z[i] * Y[i])
            # print("-----------------------")
            # 给出对应方程的矩阵形式
            a = np.array([[sigma_x4, sigma_x3_y, sigma_x2_y2, sigma_x3, sigma_x2_y, sigma_x2],
                          [sigma_x3_y, sigma_x2_y2, sigma_x_y3, sigma_x2_y, sigma_x_y2, sigma_x_y],
                          [sigma_x2_y2, sigma_x_y3, sigma_y4, sigma_x_y2, sigma_y3, sigma_y2],
                          [sigma_x3, sigma_x2_y, sigma_x_y2, sigma_x2, sigma_x_y, sigma_x],
                          [sigma_x2_y, sigma_x_y2, sigma_y3, sigma_x_y, sigma_y2, sigma_y],
                          [sigma_x2, sigma_x_y, sigma_y2, sigma_x, sigma_y, n]])
            b = np.array([sigma_z_x2, sigma_z_x_y, sigma_z_y2, sigma_z_x, sigma_z_y, sigma_z])
            # 高斯消元解线性方程
            res = np.linalg.solve(a, b)
            return res

        # 如果系数为正，前面加“+”，输出函数形式时候用
        def fun(x):
            if x >= 0:
                return '+' + str(x)
            else:
                return str(x)

        def matching_3D(x,y,z):

            n = len(x)
            print('curveSmooth之前长度  ： ', n)
            res = get_res(x, y, z, n)
            print(res)
            # 将拟合后的函数形式输出来
            print("拟合函数形式为： z=%.32s*x^2%.32s*xy%.32s*y^2%.32s*x%.32s*y%.32s" % (
                fun(res[0]), fun(res[1]), fun(res[2]), fun(res[3]), fun(res[4]), fun(res[5])))
            z1 = res[0] * x * x + res[1] * x * y + res[2] * y * y + res[3] * x + res[4] * y + res[5]
            is_del = abs(z - z1) > 1.0 * abs(z1)  # (散点数,)，[True, ......,False]
            n_del = 0  # 剔除点的个数
            X_new = []
            Y_new = []
            Z_new = []  # 剔除后的新数组
            for i in range(n):
                if not is_del[i]:
                    X_new.append(x[i])
                    Y_new.append(y[i])
                    Z_new.append(z[i])
                else:
                    n_del += 1

            if n_del > 0:
                print("\n该图应该有 %d 个点被剔除，关闭图形后进行剔除并重新拟合。" % n_del)
                print("正在重新拟合......")
                X = matching_3D(np.array(X_new), np.array(Y_new), np.array(Z_new))
            else:
                print("\n该图应该有 0 个点被剔除，拟合完成！！！！！！")
                X = pd.DataFrame()
                X[Config.WindSpeed] = np.array(X_new)
                X[Config.PitchAngle] = np.array(Y_new)
                X[Config.ActPower] = np.array(Z_new)
                print('curveSmooth之后长度： ',len(X))
            return X



        def wrapper(X):
            print('SmoothProcess.curve 进行中................')
            x,y,z = np.array(X[Config.WindSpeed].values.tolist()),\
                    np.array(X[Config.PitchAngle].values.tolist()),\
                    np.array(X[Config.ActPower].values.tolist())
            X = matching_3D(x, y, z)
            return p3(X)
        return wrapper


